/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 * This file is part of Suneido - The Integrated Application Platform
 * see: http://www.suneido.com for more information.
 *
 * Copyright (c) 2000 Suneido Software Corp.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation - version 2.
 *
 * This program is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License in the file COPYING
 * for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "database.h"
#include "interp.h"
#include "globals.h"
#include "symbols.h"
#include "surecord.h"
#include "sudb.h"
#include "catstr.h"
#include "suboolean.h"
#include "exceptimp.h"

static Lisp<int> disabled_triggers;

void Tbl::user_trigger(int tran, const Record& oldrec, /*const*/ Record& newrec, int when)
	{
	if (tran == schema_tran)
		return ;
	if (trigger == -1)
		return ;
	Value fn;
	if (! trigger)
		{
		trigger = globals(CATSTRA("TriggerWhen_", name.str()));
		fn = globals.find(trigger);
		if(! fn) 
            {
                whentrigger = 0;
        		trigger = globals(CATSTRA("Trigger_", name.str()));
		        fn = globals.find(trigger);
            }
        else whentrigger = trigger;

		if (! fn)
			{
			globals.pop(trigger); // remove it if we just added it
			whentrigger = 0;
			trigger = -1;
			return ;
			}
		for (Fields f = get_fields(); ! nil(f); ++f)
			flds.push(*f == "-" ? -1 : symnum(f->str()));
		flds.reverse();
		}
	else
		{
		fn = globals.find(trigger);
		if (! fn)
			return ;
		}
    //don't call old style triggers on WHEN_BEFORE
    if ((when == WHEN_BEFORE) && (whentrigger == 0)) return;
    
	if (member(disabled_triggers, trigger))
		return ;
	KEEPSP
	SuTransaction* t = new SuTransaction(tran);
	PUSH(t);
	PUSH(nil(oldrec) ? SuFalse : new SuRecord(oldrec, flds, t));

	SuRecord *newSuRec_ptr;
	if (nil(newrec))
	   {
		  PUSH(SuFalse);
		  newSuRec_ptr = NULL;
        }
	else
	   {
          newSuRec_ptr = new SuRecord(newrec, flds, t);
		  PUSH(newSuRec_ptr);
       }

	int paramCount;
	if (whentrigger)
	   {
          if (when == WHEN_BEFORE) 
            PUSH(SuTrue);
	      else 
            PUSH(SuFalse);
	      paramCount = 4;
        }
    else 
        paramCount = 3;
	   
	try
		{
    		Value result = fn.call(fn, CALL, paramCount, 0, 0, -1);
    		//Only reconvert newrec if TriggerWhen function return true
        	if ((result == SuTrue) && (when == WHEN_BEFORE) 
                && whentrigger && newSuRec_ptr)
        	{
                //now convert bakck newSuRec_ptr
                newrec = newSuRec_ptr->to_record(flds);
            }
		}
	catch (const Except& e)
		{
		throw Except(e, e.gcstr() + " (" + globals(trigger) + ")");
		}
	}

struct DisabledTriggers
	{
	DisabledTriggers() : n(0)
		{ }
	void push(int t)
		{
		disabled_triggers.push(t);
		++n;
		}
	~DisabledTriggers()
		{
		while (n-- > 0)
			disabled_triggers.pop();
		}
	int n;
	};

#include "prim.h"

Value su_do_without_triggers()
	{
	int nargs = 2;

	SuObject* ob = ARG(0).object();
	DisabledTriggers dt;
	for (int i = 0; ob->has(i); ++i)
		{
		char* table = ob->get(i).str();
		int trigger = globals(CATSTRA("Trigger_", table));
		dt.push(trigger);
		}

	KEEPSP
	Value block = ARG(1);
	return block.call(block, CALL, 0, 0, 0, -1);
	}
PRIM(su_do_without_triggers, "DoWithoutTriggers(object, block)");
